const fs = require("fs-extra");
const path = require("path");
const util = require("util");
const mongoConnected = require("./mongoose_connect");
const mongoModels = require("./mongoose_schemas");


/**
 * @returns {Promise<{
 * ok:Boolean,
 * msg:String,
 * data:{
 * match:{
 * MatchId:String,
 * PingQuality:String,
 * SeasonState:String,
 * StartTime:String,
 * EndTime:String,
 * isEventMode:Boolean,
 * isCustomGame:Boolean,
 * teamSize:Number,
 * weatherId:String,
 * cameraViewBehaviour:String,
 * mapName:String,
 * players:Array<{name:String,teamId:Number,accountId:String}>
 * },
 * events:Array
 * }}>}
 * @param {String} json_path 
 */
function readParsePubgJson(json_path) {
  return new Promise(async resolve => {
    fs.readFile(json_path, "utf8", (err, data) => {
      if (err) {
        debugger
      }
      /**@type {Array} */
      let d = [];
      try {
        d = JSON.parse(data);
      } catch (e) {
        return resolve({
          ok: false,
          msg: "not good json,can't parse"
        })
      }
      if (!util.isArray(d)) {
        return resolve({
          ok: false,
          msg: "not good json,it is not a array"
        })
      }
      // let LogCarePackageLand = d.filter(e=>e._T=="LogCarePackageLand")//4个
      // let LogCarePackageSpawn = d.filter(e=>e._T=="LogCarePackageSpawn")
      // let LogGameStatePeriodic = d.filter(e=>e._T=="LogGameStatePeriodic")
      let LogMatchStart = d.filter(e => e._T == "LogMatchStart")[0]
      let LogMatchEnd = d.filter(e => e._T == "LogMatchEnd")[0]
      let LogMatchDefinition = d.filter(e => e._T == "LogMatchDefinition")[0];
      let players = LogMatchStart.characters.map(e => {
        return {
          name: e.name || e.character.name,
          teamId: e.teamId || e.character.teamId,
          accountId: e.accountId || e.character.accountId
        }
      });

      // debugger
      resolve({
        ok: true,
        msg: "ok",
        data: {
          events: d,
          match: {
            MatchId: LogMatchDefinition.MatchId,
            PingQuality: LogMatchDefinition.PingQuality,
            SeasonState: LogMatchDefinition.SeasonState,
            StartTime: LogMatchStart._D,
            EndTime: LogMatchEnd._D,
            isCustomGame: LogMatchStart.isCustomGame,
            isEventMode: LogMatchStart.isEventMode,
            mapName: LogMatchStart.mapName,
            teamSize: LogMatchStart.teamSize,
            weatherId: LogMatchStart.weatherId,
            players: players,
            cameraViewBehaviour: LogMatchStart.cameraViewBehaviour
          }
        }
      });
    })
  })
}

/**
 * @returns {Promise<{ok:Boolean,msg:String}>}
 * @param {String} json_path 
 */
function insert2Mongodb(json_path) {
  let basename = path.basename(json_path);
  return new Promise(async resolve => {
    let o_read = await readParsePubgJson(json_path);
    if (!o_read.ok) {
      return resolve({
        ok: false,
        msg: `read-parse fail:${o_read.msg}`
      })
    }
    console.log("IntoMongo--", o_read.data.match.MatchId);
    console.log("Start", Date.now(), Date());


    let playersPromises = o_read.data.match.players.map(player => new Promise(async r => {
      let o_findByAccountId = await mongoModels.Player.findOne({
        account_id: player.accountId
      })

      // console.log("mongoModels.Player.findOne", "time use", (Date.now() - _t) / 1000, "sec.")
      // debugger
      if (!o_findByAccountId) {
        let p = new mongoModels.Player({
          account_id: player.accountId,
          names: [player.name],
          match_ids: [o_read.data.match.MatchId]
        });
        // debugger
        try {
          await p.save()
        } catch (e) {
          console.log("in match", o_read.data.match.MatchId, basename, "can't save player", util.inspect(p));
          return r();
        }

        // debugger
      } else {
        // debugger
        if (!o_findByAccountId.match_ids.includes(o_read.data.match.MatchId)) {
          o_findByAccountId.match_ids.push(o_read.data.match.MatchId)
        }
        if (!o_findByAccountId.names.includes(player.name)) {
          o_findByAccountId.names.push(player.name)
        }
        // o_findByAccountId.names.push('player.name')
        await o_findByAccountId.save().catch(__ => {
          debugger
        });;
        // debugger
      }
      r()
    }));


    await Promise.all(playersPromises).catch(__ => {
      console.log(o_read.data.match.MatchId, basename, "at Promise.all", util.inspect(__))
    });


    let match = new mongoModels.Match({
      match_id: o_read.data.match.MatchId,
      ping_quality: o_read.data.match.PingQuality,
      season_state: o_read.data.match.SeasonState,
      start_time: o_read.data.match.StartTime,
      end_time: o_read.data.match.EndTime,
      is_eventMode: o_read.data.match.isEventMode,
      is_customGame: o_read.data.match.isCustomGame,
      team_size: o_read.data.match.teamSize,
      weather_id: o_read.data.match.weatherId,
      camera_view_behaviour: o_read.data.match.cameraViewBehaviour,
      map_name: o_read.data.match.mapName,
      players: o_read.data.match.players.map(e => {
        return {
          name: e.name,
          team_id: e.teamId,
          account_id: e.accountId
        }
      })
    })
    try {
      await match.save()
    } catch (e) {
      console.log("失败位于match.save()", util.inspect(e), basename);
      return resolve({
        ok: false,
        msg: "fail at await match.save()"
      })
    }




    try {
      let docs = o_read.data.events.map(event => {
        return new mongoModels.Event({
          ...event,
          match_id: o_read.data.match.MatchId
        }, false)
      });
      let _t = Date.now();
      await mongoModels.Event.insertMany(docs).catch(__ => {
        debugger
      });
    } catch (e) {
      console.log("insert many fail", o_read.data.match.MatchId, util.inspect(e), basename);
      await mongoModels.Event.deleteMany({
        match_id: o_read.data.match.MatchId
      });
      return resolve({
        ok: false,
        msg: `失败位于insertMany events:${o_read.data.match.MatchId}:${basename}`
      })
    }

    let _t2 = Date.now();
    // console.log(docs.length, "events :: save use time", (_t2 - _t) / 1000, "sec.")
    // console.log("every event save use time", (_t2 - _t) / 1000 / docs.length, "sec.")

    // console.log("End", Date.now(), Date());
    // console.log("----------------------");
    console.log("OK!", basename);
    resolve({
      ok: true,
      msg: "ok"
    })
  })
}





module.exports = {
  read: readParsePubgJson,
  insert2Mongodb
}